﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using CryptoZip;

namespace CryptoZip
{
	class Program
	{
		private static int CursorTop = 0;

		static void Main(string[] args)
		{
			ShowTitle();
			Arguments arguments = new Arguments(args);

			if (arguments.IsHelpRequested)
			{
				ShowHelp();
				return;
			}

			if (arguments.HasBadParameters)
			{
				Console.WriteLine("There are missing or incorrect parameters. Please see usage help.");
				ShowHelp();
				return;
			}

			DateTime start = DateTime.Now;

			switch (arguments.EncryptionMode)
			{
				case EncryptionMode.Encrypt:
					Console.WriteLine("Compressing and encrypting {0} to {1} using...", arguments.InputFilename, arguments.InputFilename + CryptoZipLib.CRYPTOZIP_EXTENSION);
					Console.WriteLine("Compression algorithm: {0}", CryptoZipLib.COMPRESSION_ALGORITHM);
					Console.WriteLine("Encryption algorithm: {0}\r\n", CryptoZipLib.ENCRYPTION_ALGORITHM);
					CursorTop = Console.CursorTop;

					CryptoZipLib.Zip(new FileInfo(arguments.InputFilename), arguments.EncryptionKey, arguments.OutputFolder, new ProgressChangedEventHandler(ProgressChanged));
					break;

				case EncryptionMode.Decrypt:
					Console.WriteLine("Uncompressing and decrypting {0}...", arguments.InputFilename);
					CursorTop = Console.CursorTop;
					CryptoZipLib.Unzip(new FileInfo(arguments.InputFilename), arguments.EncryptionKey, arguments.OutputFolder, new ProgressChangedEventHandler(ProgressChanged));
					break;
			}

			DateTime end = DateTime.Now;
			TimeSpan time = new TimeSpan(end.Ticks - start.Ticks);
			Console.WriteLine("\r\n\r\nDone. Completed in {0:00}:{1:00}:{2:00}.{3}", time.Hours, time.Minutes, time.Seconds, time.Milliseconds);
		}

		static void ShowHelp()
		{
			Console.WriteLine("\n\rusage: cryptoziplib \n\r\t[-e (encrypt)] \n\r\t[-d (decrypt)] \n\r\t[-i input filename] \n\r\t[-k encryption key] \n\r\t[-o output folder] \n\r\t[-? show syntax summary]");
								 
		}

		static void ShowTitle()
		{
			Assembly asm = Assembly.GetExecutingAssembly();

			Console.WriteLine("{0} [Version {1}]{2}{3}. All rights reserved.{2}",	
				((AssemblyTitleAttribute)asm.GetCustomAttributes(typeof(AssemblyTitleAttribute), false)[0]).Title,
				((AssemblyFileVersionAttribute)asm.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false)[0]).Version,
				Environment.NewLine,
				((AssemblyCopyrightAttribute)asm.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false)[0]).Copyright);
		}

		static void ProgressChanged(ProgressChangedEventArgs args)
		{
			Console.CursorTop = CursorTop;
			Console.CursorLeft = 0;

			if (args.ValueType == ProgressValueType.PercentCompleted)
				Console.Write("% Completed: {0:00}", args.Value);
			else
				Console.Write("Bytes read: {0:0,0}", args.Value);
		}
	}

	internal class Arguments
	{
		public EncryptionMode EncryptionMode { get; set; }
		public string InputFilename { get; set; }
		public string EncryptionKey { get; set; }
		public string OutputFolder { get; set; }
		public bool IsHelpRequested { get; set; }
		public bool HasBadParameters { get; set; }

		public Arguments() { }

		public Arguments(string[] args) 
		{
			EncryptionMode = EncryptionMode.Encrypt;

			if (args.Length > 0)
			{
				for (int i = 0; i < args.Length; i++)
				{
					switch (args[i])
					{
						case "-?":
							IsHelpRequested = true;
							break;

						case "-e":
							EncryptionMode = EncryptionMode.Encrypt;
							break;

						case "-d":
							EncryptionMode = EncryptionMode.Decrypt;
							break;

						case "-i":
							InputFilename = args[i + 1];
							break;

						case "-k":
							EncryptionKey = args[i + 1];
							break;

						case "-o":
							OutputFolder = args[i + 1];
							break;
					}
				}

				if (!IsHelpRequested)
				{
					if (string.IsNullOrEmpty(InputFilename) || string.IsNullOrEmpty(EncryptionKey) || !File.Exists(InputFilename))
						HasBadParameters = true;
					else
						if (string.IsNullOrEmpty(OutputFolder))
							OutputFolder = new FileInfo(InputFilename).DirectoryName;
				}
			}
			else
				IsHelpRequested = true;
		}
	}

	internal enum EncryptionMode
	{
		Encrypt,
		Decrypt
	}
}
